/* 
 * File:   Polinomio.cpp
 * Author: jorgeorm
 * 
 * Created on 6 de septiembre de 2011, 10:49 PM
 */

#include "Polinomio.h"

#include <cstdlib>
#include <iostream>
#include <cstdio>
#include <stack>
#include <math.h>

using namespace std;

Polinomio::Polinomio() {
    ptr_ultimo=NULL;
}

//Polinomio::Polinomio(const Polinomio& orig) {
//}

Polinomio::~Polinomio() {
}

void Polinomio::crearPolinomio(){
    long double co;
    int n, ex;
    
    ptr_ultimo = NULL;
    cout <<"Ingrese el grado del polinomio: "<<endl;
    cin>>n;
    //Pido los valores para el polinomio
    //    
    for(int i=0; i< n; i++)
    {
        cout<<endl;
        cout<<"Ingrese el valor del coeficiente: "<<endl;
        cin>>co;
        
        cout<<endl;
        cout<<"Ingrese el valor del exponente: "<<endl;
        cin>>ex;
        
        //Crea nodo del polinomio y lo añade a la "cola".
        //
        crearNodoPolinomio(co, ex);
    }
}

void Polinomio::crearNodoPolinomio(long double co, int ex){
    POLY tmp; //nuevo termino
    tmp= new nodo_polinomio;//así hago que la asignación sea Dinámica
    tmp->coef=co;
    tmp->exp=ex;
    tmp->signtTermino= NULL;
    if(ptr_ultimo == NULL)
    {
        ptr_primero= tmp;
    }
    else ptr_ultimo->signtTermino=tmp;
    ptr_ultimo=tmp;
}

void Polinomio::resetPolinomio(){
    ptr_ultimo=NULL;
}

Polinomio Polinomio::const_mult_poly(long double cte){
    long double cteTmp;
    POLY polyTmp;
    polyTmp=ptr_primero;
    ptr_ultimo= NULL;
    
    while(polyTmp!=NULL)
    {
        cteTmp=cte*polyTmp->coef;
        if(cteTmp!=0)
            crearNodoPolinomio(cteTmp,polyTmp->exp);
        polyTmp=polyTmp->signtTermino;
    }
    
    return * this;
}

void Polinomio::imprimirPolinomio(){
    POLY tmp_actual;
    
    tmp_actual=ptr_primero;
//    cout <<"P(x)= ";
    while(tmp_actual!=NULL)
    {
        if(tmp_actual->exp==0)//ultimo 
            cout<<tmp_actual->coef;
        else
            cout<<tmp_actual->coef<<"X^"<<tmp_actual->exp;
        if(tmp_actual->signtTermino!=NULL)
            cout<<" + ";
        
        tmp_actual=tmp_actual->signtTermino;
    }
}

Polinomio Polinomio::sumaPolinomio(Polinomio poly1, Polinomio poly2)
{
    long double cteTmp;
    POLY polyTmp1, polyTmp2;
    
    polyTmp1=poly1.ptr_primero;
    polyTmp2=poly2.ptr_primero;
    
    ptr_ultimo=NULL;
    
    while(polyTmp1!= NULL && polyTmp2!=NULL)
    {
        if(polyTmp1->exp==polyTmp2->exp)
        {
            cteTmp=polyTmp1->coef+polyTmp2->coef;
            if(cteTmp!=0)
            {
                crearNodoPolinomio(cteTmp,polyTmp1->exp);
            }
            polyTmp1= polyTmp1->signtTermino;
            polyTmp2= polyTmp2->signtTermino;
        }else
        {
            if(polyTmp1->exp>polyTmp2->exp)
            {
                crearNodoPolinomio(polyTmp1->coef, polyTmp1->exp);
                polyTmp1= polyTmp1->signtTermino;
            }else
            {
                crearNodoPolinomio(polyTmp2->coef, polyTmp2->exp);
                polyTmp2= polyTmp2->signtTermino;
            }
        }
    }
    while(polyTmp1!=NULL)
    {
        crearNodoPolinomio(polyTmp1->coef, polyTmp1->exp);
        polyTmp1=polyTmp1->signtTermino;
    }
    while(polyTmp2!=NULL)
    {
        crearNodoPolinomio(polyTmp2->coef, polyTmp2->exp);
        polyTmp2=polyTmp2->signtTermino;
    }
    
    return * this;
}

Polinomio Polinomio::monomioXPolinomio(long double coef, int exp, Polinomio poly){
    long double coefTmp;
    int expTmp;
    
    POLY polinTmp;
    
    polinTmp=poly.ptr_primero;
    
    ptr_ultimo=NULL;
    
    while(polinTmp!=NULL)
    {
        coefTmp=coef*polinTmp->coef;
        expTmp=exp+polinTmp->exp;
        
        if(coefTmp!=0)
            crearNodoPolinomio(coefTmp, expTmp);
        polinTmp=polinTmp->signtTermino;
    }
    
    return * this;
}

Polinomio Polinomio::PolinomioXPolinomio(Polinomio poly1, Polinomio poly2){
    POLY polyTmp1, polyTmp2, polyCambioTmp;
//    polyTmp1=poly1.ptr_primero;
    polyTmp2=poly2.ptr_primero;
    
    //Polinomio de grado mayor 
    //
//    Polinomio poliMayorTmp;

    
    //Reordeno en caso que el polynomio 1 sea de menor grado
    //
//    if(polyTmp2->exp>polyTmp1->exp){
//        polyCambioTmp=polyTmp1;
//        polyTmp1=polyTmp2;
//        polyTmp2=polyCambioTmp;
//        poliMayorTmp=poly2;     
//    }else poliMayorTmp=poly1;
    
    int expTmp=0;
    long double coefTmp;
    
    //Pila para alamacenar los polinomios parciales resutlantes de cada monomio.
    //
    stack<Polinomio>polysParciales;
    //Polinomio temporal
    //
    Polinomio poliAuxiliarTmp;
     
    //Recorro el polinomio de menor grado y voy multiplicando sus monomios
    //
    while(polyTmp2!=NULL)
    {
        expTmp=polyTmp2->exp;
        coefTmp=polyTmp2->coef;
        
        //calculo polinomio resultant de un monomio por el polinomio
        //
        poliAuxiliarTmp= poliAuxiliarTmp.monomioXPolinomio(coefTmp,expTmp,poly1);

        polysParciales.push(poliAuxiliarTmp);//Meto en la pila el polinomio parcial
        
        polyTmp2=polyTmp2->signtTermino;// paso al siguiente termino
    }
    
    //Empiezo a realizar la suma de los polinomios parciales
    poliAuxiliarTmp= polysParciales.top();
    polysParciales.pop();
    Polinomio poliAuxiliar2Tmp;
    while(!(polysParciales.empty()))
    {
        poliAuxiliar2Tmp=polysParciales.top();
        polysParciales.pop();
        poliAuxiliarTmp=poliAuxiliarTmp.sumaPolinomio(poliAuxiliarTmp, poliAuxiliar2Tmp);
    }
    
    //Para poder hacer el return como en suma realizo una copia del polinomio
    //resultante en este polinomio
    //
    ptr_ultimo=NULL;
    polyCambioTmp=poliAuxiliarTmp.ptr_primero;
    while(polyCambioTmp!=NULL)
    {
        crearNodoPolinomio(polyCambioTmp->coef,polyCambioTmp->exp);
        polyCambioTmp=polyCambioTmp->signtTermino;
    }
    
    return * this;    
}

long double Polinomio::evaluarPolinomio(long double x_val){
    POLY tmp_actual;
    tmp_actual=ptr_primero;
    long double valorTmp=0.0;
    //    cout <<"P(x)= ";
    while(tmp_actual!=NULL)
    {
        if(tmp_actual->exp==0)//ultimo 
            valorTmp+=tmp_actual->coef;
        else
        {
            long double xAla=pow(x_val,tmp_actual->exp);
            valorTmp+=tmp_actual->coef*xAla;
        }
        
        tmp_actual=tmp_actual->signtTermino;
    }
    
    return valorTmp;
}

Polinomio Polinomio::derivadaPolinomio(Polinomio poly){
    POLY polyTmp;
    long double coefTmp;
    int expoTmp;
    
    polyTmp= poly.ptr_primero;
    ptr_ultimo=NULL;
    
    while(polyTmp!= NULL){
        coefTmp= polyTmp->coef;
        expoTmp= polyTmp->exp;
        coefTmp*=expoTmp;
        expoTmp--;
        
        if(coefTmp!=0)crearNodoPolinomio(coefTmp, expoTmp );
            
        polyTmp=polyTmp->signtTermino;
    }
    return *this;
}